<?php
/** Class <code>Url</code> simplifies working with (complicated) URLs
 * <p>
 *   Normally, creating URLs can be tough, for example you are adding parameter
 *   which already exists, resulting in two parameters with the same name.
 *   Or some parameters may always need to be passed, while others should be
 *   removed from an existing list of parameters. Class <code>Url</code> makes
 *   it easy to do these kind of things.
 * </p>
 */
class Url
{
    /** The scheme(protocol) of the url, e.g. <code>http://</code>
     * @var string
     */
    var $_protocol='http';

    /** Allowed protocols
     * @var array
     */
    var $_protocols = array('http', 'https', 'ftp');

    /** The host of the url, e.g. <code>www.example.com</code>
     * @var string
     */
    var $_host='';


    /** The file of the url, e.g. <code>script.php</code>
     * @var string
     */
    var $_fileName='';

    /** The parameters of the url (from 'GET')
     * e.g <code>a=1&b=test</code>
     * @var array
     */
    var $_params=array();

    /** The fragment of the url
     * e.g <code>top</code>
     * @var array
     */
    var $_fragment='';


    /** Constructs a new Url object.
     * @param string $url    the optional URL (a string) to base the Url on
     * @param string $strParams the optional URL (a string) with parameters only
     */
    function Url($url = '', $strParams = '')
    {
        if ($url)        
            $this->setUrl(str_replace("&amp;","&",$url), $strParams);            
        else
            $this->makeFromCurrent();
    }

    /**
     * Parses parameters in a <code>key1=value1&key2=value2&...</code> string
     * @access private
     * @param string $strParams the URL-encoded string with the parameters
     * @return void
     */
    function _parseParams($strParams)
    {
        $this->_params = array();
        $sets = explode('&', trim($strParams,'?& '));
        for ($i = 0, $n=count($sets); $i < $n; ++$i)
        {
            $pair = explode('=', $sets[$i], 2);
            if (isset($pair[1]))
                $this->_params[$pair[0]] = urldecode($pair[1]);
        }
    }

    /**
     * Parses url from the string
     * @access private
     * @param string $url url to parse
     * @return void
     */
    function _parseUrl($url)
    {
	$url = trim(str_replace("http://","",$url));
        $info = parse_url($url);

        if (array_key_exists('scheme', $info))
            $this->setProtocol($info['scheme']);
        else
            $this->setProtocol(current($this->_protocols));

        if (array_key_exists('host', $info))
            $this->setHost($info['host']);
        else
            $this->setHost(_cfg('host'));

        if (array_key_exists('path', $info))
            $this->setFileName($info['path']);
        else
            $this->setFileName('index.php');

        if (array_key_exists('query', $info))
            $this->_parseParams($info['query']);
        else
            $this->_params = array();

        if (array_key_exists('fragment', $info))
            $this->setFragment($info['fragment']);
        else
            $this->setFragment('');			
    }

    /** Set a new value to the Url
     * @param string $url    the URL (a string) to base this Url on
     * @param string $strParams the optional string of parameters (URL-encoded)
     * @return void
     */
    function setUrl($url, $strParams = '')
    {
        // Create the new URL
        $this->_parseParams($strParams);
        $this->_parseUrl($url);
    }

    /** Set the Url to the URL of the current page;
     * @return void
     */
    function makeFromCurrent()
    {
        $url = '';
        if (array_key_exists('SCRIPT_NAME',  $_SERVER))
            $url .= $_SERVER['SCRIPT_NAME'];
        if (array_key_exists('QUERY_STRING', $_SERVER))
            $url .= '?'. $_SERVER['QUERY_STRING'];
        $this->_parseUrl($url);
        $this->setProtocol(isset($_SERVER['HTTPS']) ? 'https' : 'http');
        $this->setHost(_cfg('host'));
    }

// GET/SET functions


    /** Retruns protocol
     * @return string scheme of the url
     */
    function getProtocol()
    {
        return $this->_protocol;
    }

    /** Sets protocol.
     * @param string $protocol new protocol
     * @return void
     */
    function setProtocol($protocol)
    {
        if (in_array($protocol, $this->_protocols))
            $this->_protocol = $protocol;
    }

    /** Sets the host for the Url
     * @param string $host
     * @return void
     */
    function setHost($host)
    {
        $this->_host = trim($host,'/ ');
    }

    /** Returns host of the url
     * @return string host
     */
    function getHost()
    {
        return $this->_host;
    }


    /** Returns dirs/filename of the url
     * @return string file name
     */
    function getFileName()
    {
        return $this->_fileName;
    }

    /** Sets the dirs/filename for the Url
     * @param string $fileName
     * @return void
     */
    function setFileName($fileName)
    {
        $this->_fileName = trim($fileName, '/ ');

    }

    /** Updates the value of a parameter
     * @param string $name  the name of the parameter to update
     * @param string $name the new value of the parameter or null if the parameter should be deleted
     * @return void
     */
    function setParam($name, $val = null)
    {
        $this->_params[$name] = $val;        
        if (null === $val)
            unset($this->_params[$name]);
    }

    /** Gets value of a parameter
     * @param string $name  the name of the parameter
     * @return string param value if any or '' if no value
     */
    function getParam($name)
    {
        return (empty($this->_params[$name]) ? '' : $this->_params[$name]);
    }

    /** Returns a fragment of the url
     * @return string fragment
     */
    function getFragment()
    {
        return $this->_fragment;
    }

    /** Sets the fragment of the Url
     * @param string $fragment
     * @return void
     */
    function setFragment($fragment)
    {
        $this->_fragment = $fragment;

    }

    /** Returns a string representation of the URL
     * @return string
     */
    function getUrl()
    {
        $url = $this->getProtocol().'://'.$this->getHost().'/'.$this->getFileName();
        $params = array();        
        foreach ($this->_params as $name => $val)
        {
            if (!empty($name))
                $params[] = $name . '=' . urlencode($val);
        }
        if (sizeof($params))
            $url .= '?' . join('&', $params);
        if ($this->_fragment)
            $url .= '#'.urlencode($this->_fragment);
        return $url;
    }
    
    /**
     * Clears url params except specified
     *
     * @param mixed $exclude name of param or array of names
     */
    function clearParams($exclude='mod')
    {
        if (!is_array($exclude))
            $exclude = array($exclude);
              
        foreach ($this->_params as $name => $val)
        {        
            if (!in_array($name, $exclude))
                unset($this->_params[$name]);
        }   
    }

    function compare($url)
    {
        foreach ($url->_params as $p => $v)
            if ($this->_params[$p] != $v)
                return false;
        return true;
    }
}
?>